home *** CD-ROM | disk | FTP | other *** search
- #include "ocheaders.h"
- #include <stdio.h>
- #include <ctype.h>
- #include "BDDISPIDs.h"
- #include "CBaseControl.h"
- #include "CConsoleControl.h"
- #include "BDConsts.h"
- #include "BDUtils.h"
- #include <LArray.h>
- #include "CConnectionPoint.h"
- #include "CCPContainer.h"
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::CConsoleControl
- //
-
- CConsoleControl::CConsoleControl(void) :
- CBaseControl()
- {
- m_Cookie = 0;
- m_Message = NULL;
- m_NumMsgs = 0;
- m_CurrentMsg = 0;
-
- mClickSource = NULL;
-
- mIsIdling = false;
-
- mID[0] = 0;
-
- CConnectionPoint* connectionPoint;
- IConnectionPoint* cp;
- short i;
- CCPContainer* containerObj = nil;
-
- // Create the new connection point container object
- containerObj = new CCPContainer(NUM_CONNECTIONS);
-
- // Snag the interface pointer
- if ( containerObj )
- containerObj->QueryInterface(IID_IConnectionPointContainer, &mCPContainerP);
-
- // if we have a container object, allocate the connection points
- if ( mCPContainerP )
- // We support 1 connection point
- containerObj->AddConnectionPoint(IID_IDoMenuEvents);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::~CConsoleControl
- //
-
- CConsoleControl::~CConsoleControl()
- {
- if ( mIsIdling )
- mContainerSiteP->SetIdleTime(RemoveAllIdlers, 0);
-
- if (m_Message)
- {
- DisposeHandle((Handle) m_Message);
- m_Message = NULL;
- }
-
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IUnknown::QueryInterface
- //
- // Returns a pointer to the specified interface on a component to which a
- // client currently holds an interface pointer.
- //
-
- STDMETHODIMP
- CConsoleControl::QueryInterface(REFIID RefID, void** Obj)
- {
- if ( RefID == IID_IDidMenuEvents ) // an incoming interface
- {
- *Obj = (void*) (IDidMenuEvents*) this;
- AddRef();
-
- return ResultFromScode(S_OK);
- }
- else
- return CBaseControl::QueryInterface(RefID, Obj);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IObjectWithSite::SetSite
- //
- STDMETHODIMP
- CConsoleControl::SetSite(IUnknown* inClientSite)
- {
- CBaseControl::SetSite(inClientSite);
-
- if ( mContainerSiteP )
- mIsIdling = ( mContainerSiteP->SetIdleTime(0, 0) == S_OK );
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IControl::Draw
- //
-
- STDMETHODIMP
- CConsoleControl::Draw(DrawContext* Context)
- {
- FontInfo fInfo;
- short curX;
- short curY;
- short i;
- short msgIndex;
- char theState;
- RgnHandle saveClipRgn;
- Rect controlRect, newClipRect;
- Boolean overlap = false;
-
- if (Context->DrawAspect != DVASPECT_CONTENT)
- return DV_E_DVASPECT;
-
- // Set the font and size
- ::TextFont(applFont);
- ::TextFace(0);
- ::TextMode(srcCopy);
- ::TextSize(9);
- ::GetFontInfo(&fInfo);
-
- // Erase the area and outline the frame
- ::EraseRect(&Context->Location);
- ::PenSize(1, 1);
- ::FrameRect(&Context->Location);
-
- // Save the current clip
- saveClipRgn = ::NewRgn();
- ::GetClip(saveClipRgn);
-
- controlRect = Context->Location;
- ::InsetRect(&controlRect, 3, 3);
- overlap = SectRect(&controlRect, &((*saveClipRgn)->rgnBBox), &newClipRect);
-
- if (overlap)
- {
- // Reset the clip
- ::ClipRect(&newClipRect);
- }
-
- // Initialize the message storage, if not already done
- if (!m_Message) {
- InitMessages(Context);
- }
-
- curX = Context->Location.left+3;
- curY = Context->Location.top+3;
-
- // Draw the messages, one on each line
- curY += fInfo.ascent;
-
- msgIndex = (m_CurrentMsg + 1) % m_NumMsgs;
- theState = ::HGetState((Handle) m_Message);
- ::HLock((Handle) m_Message);
-
- for (i = 1; i <= m_NumMsgs; i++)
- {
- ::MoveTo(curX, curY);
- ::DrawString(*(*m_Message + msgIndex));
- curY += fInfo.ascent + fInfo.descent + fInfo.leading;
- msgIndex = (msgIndex + 1) % m_NumMsgs;
- }
-
- ::HSetState((Handle) m_Message, theState);
-
- if (overlap)
- {
- // Restore the clip
- ::SetClip(saveClipRgn);
- }
- ::DisposeRgn(saveClipRgn);
-
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IControl::OnEvent
- //
-
- STDMETHODIMP
- CConsoleControl::DoIdle(Uint32 IdleRefCon)
- {
- // if the client site has been set and the advisory cookie has not,
- // enumerate the other controls in this container to find the one we want
- // to connect to
- if (mContainerSiteP != NULL && m_Cookie == 0)
- {
- IUnknown* testControl;
- IEnumUnknown* enumU;
-
- if ( !mContainerP )
- {
- mContainerSiteP->GetContainer(&mContainerP);
- if ( mContainerP )
- mContainerP->AddRef();
- else
- return S_OK;
- }
-
- // Enumerate the objects
- if ( SUCCEEDED(mContainerP->EnumControls(nil, OLECONTF_EMBEDDINGS, &enumU)) )
- {
- IConnectionPointContainer* cpContainer = nil;
-
- while ( enumU->Next(1, &testControl, nil) == NOERROR )
- {
- // Try to get a connection point container from the control
- testControl->QueryInterface(IID_IConnectionPointContainer, (void**) &cpContainer);
-
- // if it has one, this may be it
- if ( cpContainer )
- {
- IConnectionPoint* cp = nil;
-
- // See if this connection point container
- // has a connection point with the outgoing interface we want
- cpContainer->FindConnectionPoint(IID_IDidMenuEvents, &cp);
-
- // if we got it, set an advise connection on the outgoing interface
- if ( cp )
- {
- IUnknown* unk;
-
- this->QueryInterface(IID_IUnknown, (void**) &unk);
- cp->Advise(unk, &m_Cookie);
- }
- }
- }
-
- // Don't forget to release
- enumU->Release();
- }
- else
- m_Cookie = -1;
- }
-
- // if we're hooked up, discontinue idling
- if ( m_Cookie != 0 )
- {
- mContainerSiteP->SetIdleTime(RemoveAllIdlers, 0);
- mIsIdling = false;
- }
-
- return S_OK;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IPersistPropertyBag::Load
- //
-
- STDMETHODIMP
- CConsoleControl::Load(IPropertyBag* propertyBag, IErrorLog* errorLog)
- {
- CBaseControl::Load(propertyBag, errorLog);
-
- char propertyString[Str255BufferLength];
-
- if ( ::LoadPropertyString(propertyBag, "sourceid", propertyString, Str255StringLength, errorLog) )
- {
- strcpy((char*)(&mID[1]), propertyString);
- mID[0] = strlen(propertyString);
- }
-
- return ResultFromScode(S_OK);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::IDidMenuEvents::Click
- //
-
- STDMETHODIMP
- CConsoleControl::Click(IUnknown* Source, PlatformEvent* Event, char * originatorName, const CMenuItem & Item)
- {
- Str255 theMessage;
-
- // Add message to tell which object (button) caused the popup, which item in the popup
- // was clicked, and the text of that item.
-
- sprintf((char *)theMessage, "%s%s%s%s%s%ld%s%s%s%s",
- "Received Popup Click Event:",
- " Originator = '", originatorName, "', ",
- " Menu item number = ", Item.itemNumber, ", ",
- " Menu item text = '", Item.itemText, "'");
- // sprintf((char *)theMessage, "%s, item number %d: %s", originatorName, Item.itemNumber, Item.itemText);
- c2pstr((char *)theMessage);
- AddMessage(theMessage);
-
- // Parse the text of the selected menu item to determinw whether to Append
- // a menu item, remove the last one, or clear the whole menu.
-
- Boolean fire = false;
- long eventID = ParseMenuItem(Item);
-
- switch ( eventID )
- {
- case DISPID_CLEAR:
- {
- sprintf((char *)theMessage, "Firing event to clear '%s' popup", originatorName);
- c2pstr((char *)theMessage);
- AddMessage(theMessage);
-
- fire = true;
-
- break;
- }
-
- case DISPID_REMOVEITEM:
- {
- mTempMenuItem.itemNumber = Item.itemNumber;
- strcpy(mTempMenuItem.itemText, Item.itemText);
-
- sprintf((char *)theMessage, "Firing event to remove menu item number %d in '%s' popup", Item.itemNumber, originatorName);
- c2pstr((char *)theMessage);
- AddMessage(theMessage);
-
- fire = true;
-
- break;
- }
-
- case DISPID_ADDITEM:
- {
- char itemText[256];
- sprintf(itemText, "This item, number %ld, created by Console", Item.itemNumber);
-
- mTempMenuItem.itemNumber = Item.itemNumber;
- strcpy(mTempMenuItem.itemText, itemText);
-
- sprintf((char *)theMessage, "Firing event to add menu item number %d in '%s' popup", Item.itemNumber, originatorName);
- c2pstr((char *)theMessage);
- AddMessage(theMessage);
-
- fire = true;
-
- break;
- }
-
- default:
- break;
- }
-
- if ( fire )
- {
- // note which control sent us the Click message in the first place,
- // because that's the only one we want to fire an event at in return.
- if ( SUCCEEDED( Source->QueryInterface(IID_IDoMenuEvents, (void**) &mClickSource) ))
- FireEvent(IID_IDoMenuEvents, eventID, Event);
- }
-
- FinishEvent();
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::FireEvent
- //
-
- STDMETHODIMP
- CConsoleControl::FireEvent(REFIID RefID, long EventID, PlatformEvent* Event)
- {
- IEnumConnectionPoints* enumCP;
- IEnumConnections* enumC;
- CONNECTDATA connectData;
- IUnknown* eventTarget;
- IConnectionPoint* connectionPoint;
-
- // Get an enumerator for the connection points
- if ( SUCCEEDED(mCPContainerP->EnumConnectionPoints(&enumCP)) )
- {
- // Loop through all the connection points for this control
- while ( enumCP->Next(1, &connectionPoint, nil) == NOERROR )
- {
- // Get all the connections for this connection point
- if ( SUCCEEDED( connectionPoint->EnumConnections(&enumC) ))
- {
- // Loop through all the connections for this connection point
- while ( enumC->Next(1, &connectData, nil) == NOERROR )
- {
- // Get the interface implementation for this connection
- // if successful, fire the event
- if ( SUCCEEDED( connectData.pUnk->QueryInterface(RefID, (void**) &eventTarget) ))
- FireOneEvent(RefID, EventID, eventTarget, Event);
- }
-
- // Release the enumerator
- enumC->Release();
- }
- }
-
- enumCP->Release();
- }
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::FireOneEvent
- //
-
- STDMETHODIMP
- CConsoleControl::FireOneEvent(REFIID RefID, long EventID, IUnknown* EventTarget, PlatformEvent* Event)
- {
- IDoMenuEvents* popTarget = (IDoMenuEvents*) EventTarget;
- IUnknown* unk;
-
- // right now, we're only concerned with firing events back at objects that
- // sent us a Click message.
- if ( mClickSource )
- {
- if ( EventTarget == mClickSource )
- {
- this->QueryInterface(IID_IUnknown, (void**) &unk);
-
- switch ( EventID )
- {
- case DISPID_CLEAR:
- popTarget->Clear(unk, Event);
- break;
-
- case DISPID_REMOVEITEM:
- popTarget->RemoveItem(unk, Event, mTempMenuItem);
- break;
-
- case DISPID_ADDITEM:
- popTarget->AddItem(unk, Event, mTempMenuItem);
- break;
- }
-
- mClickSource = NULL; // reset for next event
- }
- }
- else // no mClickSource -- handle unspecific messages
- ; // none yet
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::FinishEvent
- //
-
- void CConsoleControl::FinishEvent(void)
- {
- InvalAllContexts();
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::AddMessage
- //
-
- void CConsoleControl::AddMessage(Str255 inMessage)
- {
- char theState;
-
- if (!m_Message)
- InitMessages(nil);
-
- // Lock the message storage
- theState = ::HGetState((Handle) m_Message);
- ::HLock((Handle) m_Message);
-
- // Advance the message pointer
- m_CurrentMsg++;
- if (m_CurrentMsg >= m_NumMsgs)
- m_CurrentMsg = 0;
-
- // Copy the message into the message storage
- ::PLstrcpy(*(*m_Message + m_CurrentMsg), inMessage);
-
- // Unlock the message storage
- ::HSetState((Handle) m_Message, theState);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::InitMessages
- //
-
- void CConsoleControl::InitMessages(DrawContext* inContext)
- {
- // Initialize the message storage, if not already done
- if (!m_Message)
- {
- DrawContext Context = {(PortType) 0};
- short height = 0;
- FontInfo fInfo;
- long index = 1;
- ErrorCode Result = S_OK;
-
- if ( inContext )
- Context = *inContext;
- else
- Result = mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &Context);
-
- if ( Result == S_OK )
- {
- // Set the font and size
- ::TextFont(applFont);
- ::TextFace(0);
- ::TextSize(9);
- ::GetFontInfo(&fInfo);
-
- // Figure the number of lines that can be displayed in the control
- height = Context.Location.bottom - Context.Location.top - 6;
- m_NumMsgs = height/(fInfo.ascent + fInfo.descent + fInfo.leading);
-
- // Add one more line if the leading is the only part that won't fit
- if (height - m_NumMsgs * (fInfo.ascent + fInfo.descent + fInfo.leading) >=
- (fInfo.ascent + fInfo.descent)) {
- m_NumMsgs++;
- }
-
- // Allocate the memory
- if (m_NumMsgs > 0)
- {
- m_Message = (Str255**) ::NewHandleClear(sizeof(Str255) * m_NumMsgs);
- m_CurrentMsg = m_NumMsgs ? m_NumMsgs - 1: 0;
- }
- else
- m_NumMsgs = 0;
-
- if ( !inContext )
- mContainerSiteP->ReleaseContext(&Context);
- }
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CConsoleControl::ParseMenuItem
- //
-
- long CConsoleControl::ParseMenuItem(const CMenuItem & item)
- {
- long id = 0;
-
- // get the leading characters, in lowercase. kLeadingLength is set
- // big enough to accommodate the strings we're looking for.
- const short kLeadingLength = 16;
- char leadingChars[kLeadingLength+1];
- long itemTextLength = strlen(item.itemText);
- strncpy(leadingChars, item.itemText, (itemTextLength < kLeadingLength ? itemTextLength : kLeadingLength));
- for ( short i = 0; i < strlen(leadingChars); i++ )
- leadingChars[i] = tolower(leadingChars[i]);
-
- if ( strstr(leadingChars, "add") == leadingChars ) // does the string start with "add" ?
- id = DISPID_ADDITEM;
- else if ( strstr(leadingChars, "remove") == leadingChars ) // does the string start with "add" ?
- id = DISPID_REMOVEITEM;
- else if ( strstr(leadingChars, "clear") == leadingChars ) // does the string start with "add" ?
- id = DISPID_CLEAR;
-
- return id;
- }
-